#include "postgres.h"
#include "utils/hfs.h"

#include <lmdb.h>


#define MAXREADERS 512
#define MAPSIE (uint64)1<<40
#define DEFAULTPAGEPATH "/tmp/pagedb"
#define DEFAULTWALPATH "/tmp/waldb"
#define PAGE 1
#define WAL 2
#define BLKSZ 8192

#define DROP 1
#define TRUNCATE 2
#define EVICT 3
#define SDLEN 1024
#define SDNUM 128

#define SecondBufferTableHashPartition(hashcode) \
	((hashcode) % NUM_LOCK_PARTITIONS)
#define SecondBufferMappingPartitionLock(hashcode) \
	(&SecondBufferMainLWLockArray[SecondBufferTableHashPartition(hashcode)].lock)

extern char *lmdb_page_directory;
extern char *lmdb_wal_directory;
extern Size SNBuffers;

/*
for secondbufferhash code
*/
typedef struct SdPageKey
{
    uint32 dbid;
    uint32 relid;
    uint32 forkno;
    uint32 blkno;
} SdPageKey;

typedef struct SdPageKeyEntity
{
    SdPageKey spk;
    struct SdPageKeyEntity *next;
} SdPageKeyEntity;

typedef struct SdPageKeyList
{
    SdPageKeyEntity *head;
    SdPageKeyEntity *tail;
} SdPageKeyList;

typedef struct LdPageKey
{
    SdPageKey sk;
} LdPageKey;

typedef struct WalLdPageKey
{
    SdPageKey sk;
    uint64 pageLsn;
    uint8   partition;
} WalLdPageKey;

typedef struct OriginDPageKey
{
    PageKey pk;
    int opration;
} OriginDPageKey;

typedef struct SdPageValue
{
    SdPageKey   pk;
    bool        canDelete;
    uint8 pagecontent[BLKSZ];
} SdPageValue;



typedef struct DPageKey
{
    PageKey pk;
    bool pagedeleted;
    uint8_t operation;
} DPageKey;



typedef struct kvStruct {
    LdPageKey lpk;
    uint8_t *buf;
    int32 length;
    uint64_t lsn;
} kvStruct;

//extern SingleKeyArray *MultiKeyArrays;

extern MDB_env *pageEnv;
extern MDB_env *walEnv;

extern MDB_dbi pageDbi;
extern MDB_dbi walDbi;

extern MDB_txn *pageTxn;
extern MDB_txn *walTxn;
extern MDB_cursor *cursor;

// MDB_stat mst;
// MDB_cursor_op op;

extern void InitSecondBufferMeta(void);
extern void InitSecondBufferHash(void);

extern void InitDPageKeyArray(void);

extern void InitPageDBEnv(void);
extern void InitWalDBEnv(void);

extern void storeWalInLocalBuffer(kvStruct *ks,int32 length);
extern void ReceivePageFromDataBuffer(PageKey *pk, uint8_t *buffer); // when evict one page out databuffer, we should call this to store the page.
extern void GetPageFromCurrentNode(PageKey pk,Bufrd *bufrd);                    // async delete old version page and wal. we should call this when move page from ld/sdb to db.
extern Bufrd GetWalFromLd(PageKey *pk);
extern Bufrd GetWalFromLocalBuffer(WalLdPageKey *pk, uint64_t replyLsn);
extern void AddOneItemToDPArray(OriginDPageKey pk);
extern void SecondBufferMain(void);
extern void ClosePageDBEnv(void);
extern void CloseWalDBEnv(void);

extern void CreateSecondBufferLWLocks(void);
extern Size SecondBufferLWLockShmemSize(void);
extern Size SecondBufferShmemSize(void);
extern uint64_t SwapLsnFromLittleToBig(uint64_t lsn);
extern uint64_t SwapLsnFromBigToLittle(uint64_t lsn);
extern void SendInvalWal(WalLdPageKey *walkey);
extern void SendInvalPage(LdPageKey *ldKey);
extern void *CleanWalsInLmdb(void *arg);
extern void *CleanPagesInLmdb(void *arg); 
